package org.libtiff.jai.codec;
/*
 * XTIFF: eXtensible TIFF libraries for JAI.
 * 
 * The contents of this file are subject to the  JAVA ADVANCED IMAGING
 * SAMPLE INPUT-OUTPUT CODECS AND WIDGET HANDLING SOURCE CODE  License
 * Version 1.0 (the "License"); You may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.sun.com/software/imaging/JAI/index.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License. 
 *
 * The Original Code is JAVA ADVANCED IMAGING SAMPLE INPUT-OUTPUT CODECS
 * AND WIDGET HANDLING SOURCE CODE. 
 * The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 * Portions created by: Niles Ritter 
 * are Copyright (C): Niles Ritter, GeoTIFF.org, 1999,2000.
 * All Rights Reserved.
 * Contributor(s): Niles Ritter
 */


import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.TreeMap;
import java.util.Iterator;
import org.libtiff.jai.util.JaiI18N;

// Warning: media libraries subject to change
import com.sun.media.jai.codec.SeekableStream;  

/**
 * XTIFFDirectory is an extensible TIFF directory object. This
 * class may be extended without changing the XTIFF codec by
 * overriding the XTIFFFactory instance registered in this
 * class. In addition, this class is the repository of all
 * XTIFFTileCodec's which may be augmented with new codecs,
 * again without overriding the ImageCodec. If the jai "tiff"
 * codec has been overridden through the
 * <code>XTIFFDescriptor.register()</code> method, each XTIFF image will
 * possess a property called "tiff.directory" which will be
 * an object of the type created by the factory. The class is
 * declared as serializable to permit its transmission to remote
 * images as a set of parameters to the codec, and to be able
 * to survive as an instantiated property of the RenderedImage.
 *
 * @author Niles Ritter
 * @see XTIFFDescriptor
 * @see XTIFFField
 * @see XTIFFTileCodec
 * @see XTIFFFactory
 */
public class XTIFFDirectory extends Object 
implements java.io.Serializable
{
    private int imageType;

	/** default directory factory */
    protected static XTIFFFactory factory = new XTIFFFactory();

    protected static Hashtable tileCodecs = new Hashtable();

    /** The stream being read. Not persisted */
    transient protected SeekableStream stream;

    /** A boolean storing the endianness of the stream. */
    boolean isBigEndian;

    /** A boolean indicating tiled tagset  */
    boolean _isTiled=false;
    
    /** for dynamically adding fields in sorted order*/
    TreeMap fieldIndex=new TreeMap();

    /** The default constructor. Publicized for Serializability */
    public XTIFFDirectory() {}

    private static boolean isValidEndianTag(int endian) {
        return ((endian == 0x4949) || (endian == 0x4d4d));
    }

	/**
	 * If true this image uses TIFF 6.0 tiling
	 */
    public boolean isTiled() {
	return _isTiled;
    }

	/**
	 * reads the TIFF header. Not likely to be overridden.
	 */
    protected void readHeader() throws IOException
    {

        // Read the TIFF header
        stream.seek(0L);
        int endian = stream.readUnsignedShort();
        if (!isValidEndianTag(endian)) {
            throw new 
		IllegalArgumentException(JaiI18N.getString("XTIFFDirectory1"));
        }
        isBigEndian = (endian == 0x4d4d);

	// Verify that Douglas Addams still has influence in software:
        int magic = readUnsignedShort(stream);
        if (magic != 42) {
            throw new 
		IllegalArgumentException(JaiI18N.getString("XTIFFDirectory2"));
        }

    }

    /**
     * Constructs a XTIFFDirectory from a SeekableStream.
     * The directory parameter specifies which directory to read from
     * the linked list present in the stream; directory 0 is normally
     * read but it is possible to store multiple images in a single
     * TIFF file by maintaing multiple directories.
     *
     * @param stream a SeekableStream to read from.
     * @param directory the index of the directory to read.
     */
    protected XTIFFDirectory(SeekableStream stream, int directory)
        throws IOException {

        this.stream = stream;
        long global_save_offset = stream.getFilePointer();
        long ifd_offset;

	readHeader();

        // Get the initial ifd offset as an unsigned int (using a long)
        ifd_offset = readUnsignedInt(stream);
        
        for (int i = 0; i < directory; i++) {
            if (ifd_offset == 0L) {
                throw new 
		   IllegalArgumentException(JaiI18N.getString("XTIFFDirectory3"));
            }
            
            stream.seek(ifd_offset);
            int entries = readUnsignedShort(stream);
            stream.skip(12*entries);

            ifd_offset = readUnsignedInt(stream);
        }

        stream.seek(ifd_offset);
        initialize();
        stream.seek(global_save_offset);
    }

    /**
     * Constructs a XTIFFDirectory by reading a SeekableStream.
     * The ifd_offset parameter specifies the stream offset from which
     * to begin reading; this mechanism is sometimes used to store
     * private IFDs within a TIFF file that are not part of the normal
     * sequence of IFDs.
     *
     * @param stream a SeekableStream to read from.
     * @param ifd_offset the long byte offset of the directory.
     */
    protected XTIFFDirectory(SeekableStream stream, long ifd_offset)
        throws IOException {
        this.stream = stream;
        long global_save_offset = stream.getFilePointer();

	readHeader();

        stream.seek(ifd_offset);
        initialize();
        stream.seek(global_save_offset);
    }

    private static final int[] _sizeOfType = {
        0, //  0 = n/a
        1, //  1 = byte
        1, //  2 = ascii
        2, //  3 = short
        4, //  4 = long
        8, //  5 = rational
        1, //  6 = sbyte
        1, //  7 = undefined
        2, //  8 = sshort
        4, //  9 = slong
        8, // 10 = srational
        4, // 11 = float
        8  // 12 = double 
    };

	/**
	 * Return the size of a data type. Extend if you
	 * need to define new TIFF field types. Also override
	 * the createField() method of the XTIFFFactory, the
	 * XTIFFField class, and the readFieldValue() method here.
	 * @param type the XTIFFField type code
	 * @see XTIFFField
	 * @see XTIFFFactory
	 */
    public int sizeOfType(int type) 
       throws  ArrayIndexOutOfBoundsException 
    {
	return _sizeOfType[type];
    }

	/**
	 * Create and add a TIFF field to this directory.
	 * @param tag the TIFF tag listed in XTIFF
	 * @param type the TIFF field type listed in XTIFFField
	 * @param count the number of values in array obj
	 * @param obj the array of values
	 * @see XTIFFField
	 * @see XTIFF
	 */
    public void addField(int tag,int type,int count,Object obj) {
	addField( factory.createField(tag,type,count,obj));
    }
	/**
	 * Create a TIFF field 
	 * @param tag the TIFF tag listed in XTIFF
	 * @param type the TIFF field type listed in XTIFFField
	 * @param count the number of values in array obj
	 * @param obj the array of values
	 * @see XTIFFField
	 * @see XTIFF
	 */
    public static XTIFFField createField(int tag,int type,int count,Object obj){
	return factory.createField(tag,type,count,obj);
    }

	/**
	 * Add an existing TIFF field to this directory.
	 * @param type the XTIFFField type code
	 * @see XTIFFField
	 */
    public void addField( XTIFFField field ) {
	fieldIndex.put(new Integer(field.tag),field);
    }

	/**
	 * Initialize the directory from a stream
	 */
    protected void initialize() throws IOException {
	XTIFFField field;
        long nextTagOffset;

        int numEntries = readUnsignedShort(stream);

        for (int i = 0; i < numEntries; i++) {

	    try {
	     	field = readField();
	    } catch (ArrayIndexOutOfBoundsException ae) {
		// if the data type is unknown we should skip this TIFF Field
		continue;
	    }
            addField(field);
        }
    }

    /** Returns the number of directory entries. */
    public int getNumEntries() {
        return fieldIndex.size();
    }


    /**
     * Returns the value of a given tag as a XTIFFField,
     * or null if the tag is not present.
     */
    public XTIFFField getField(int tag) {
        return (XTIFFField)fieldIndex.get(new Integer(tag));
    }

    /**
     * Returns true if a tag appears in the directory. 
     */
    public boolean isTagPresent(int tag) {
        return fieldIndex.containsKey(new Integer(tag));
    }

    /**
     * Returns an ordered array of ints indicating the tag
     * values.
     */
    public int[] getTags() {
        int[] tags = new int[fieldIndex.size()];
        Iterator iter = fieldIndex.keySet().iterator();
        int i = 0;
        while (iter.hasNext()) {
            tags[i++] = ((Integer)iter.next()).intValue();
        }
        return tags;
    }

    /**
     * Returns an array of XTIFFFields containing all the fields
     * in this directory.
     */
    public XTIFFField[] getFields() {
        XTIFFField[] fields = new XTIFFField[fieldIndex.size()];
        Iterator iter = fieldIndex.values().iterator();
        int i = 0;
        while (iter.hasNext()) {
            fields[i++] = (XTIFFField)iter.next();
        }
        return fields;
    }

    /**
     * Returns the value of a particular index of a given tag as a
     * byte.  The caller is responsible for ensuring that the tag is
     * present and has type XTIFFField.TIFF_SBYTE, TIFF_BYTE, or
     * TIFF_UNDEFINED.
     */
    public byte getFieldAsByte(int tag, int index) {
        return (getField(tag).getAsBytes())[index];
    }

    /**
     * Returns the value of index 0 of a given tag as a
     * byte.  The caller is responsible for ensuring that the tag is
     * present and has  type XTIFFField.TIFF_SBYTE, TIFF_BYTE, or
     * TIFF_UNDEFINED.
     */
    public byte getFieldAsByte(int tag) {
        return getFieldAsByte(tag, 0);
    }

    /**
     * Returns the value of a particular index of a given tag as a
     * long.  The caller is responsible for ensuring that the tag is
     * present and has type TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED,
     * TIFF_SHORT, TIFF_SSHORT, TIFF_SLONG or TIFF_LONG.
     */
    public long getFieldAsLong(int tag, int index) {
        return getField(tag).getAsLong(index);
    }

    /**
     * Returns the value of index 0 of a given tag as a
     * long.  The caller is responsible for ensuring that the tag is
     * present and has type TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED,
     * TIFF_SHORT, TIFF_SSHORT, TIFF_SLONG or TIFF_LONG.
     */
    public long getFieldAsLong(int tag) {
        return getFieldAsLong(tag, 0);
    }

    /**
     * Returns the value of a particular index of a given tag as a
     * float.  The caller is responsible for ensuring that the tag is
     * present and has numeric type (all but TIFF_UNDEFINED and
     * TIFF_ASCII).
     */
    public float getFieldAsFloat(int tag, int index) {
        return getField(tag).getAsFloat(index);
    }

    /**
     * Returns the value of index 0 of a given tag as a float.  The
     * caller is responsible for ensuring that the tag is present and
     * has numeric type (all but TIFF_UNDEFINED and TIFF_ASCII).
     */
    public float getFieldAsFloat(int tag) {
        return getFieldAsFloat(tag, 0);
    }

    /**
     * Returns the value of a particular index of a given tag as a
     * double.  The caller is responsible for ensuring that the tag is
     * present and has numeric type (all but TIFF_UNDEFINED and
     * TIFF_ASCII).
     */
    public double getFieldAsDouble(int tag, int index) {
        return getField(tag).getAsDouble(index);
    }

    /**
     * Returns the value of index 0 of a given tag as a double.  The
     * caller is responsible for ensuring that the tag is present and
     * has numeric type (all but TIFF_UNDEFINED and TIFF_ASCII).
     */
    public double getFieldAsDouble(int tag) {
        return getFieldAsDouble(tag, 0);
    }

	/**
	 * TIFF field-value reader. Override if there are
	 * new field types. Also override sizeOfType() and,
	 * possibly the createField method of the factory,
	 * if the field needs new accessors.
	 */
    public Object readFieldValue(int tag,int type,int count)
       throws IOException, ArrayIndexOutOfBoundsException 
    {
	    int j;
            Object obj = null;

            switch (type) {
            case XTIFFField.TIFF_BYTE:
            case XTIFFField.TIFF_SBYTE:
            case XTIFFField.TIFF_UNDEFINED:
            case XTIFFField.TIFF_ASCII:
                byte[] bvalues = new byte[count];
                stream.readFully(bvalues, 0, count);

		if (type == XTIFFField.TIFF_ASCII) {

		    // Can be multiple strings
		    int index = 0, prevIndex = 0;
		    Vector v = new Vector();

		    while (index < count) {
			
                        while ((index < count) && (bvalues[index++] != 0));

			// When we encountered zero, means one string has ended
			v.add(new String(bvalues, prevIndex, 
					 (index - prevIndex)) );
			prevIndex = index;
		    }

		    count = v.size();
		    String strings[] = new String[count];
		    for (int c = 0 ; c < count; c++) {
			strings[c] = (String)v.elementAt(c);
		    }

		    obj = strings;
		} else {
		    obj = bvalues;
		}

                break;

            case XTIFFField.TIFF_SHORT:
                char[] cvalues = new char[count];
                for (j = 0; j < count; j++) {
		    cvalues[j] = (char)(readUnsignedShort(stream));
                }
                obj = cvalues;
                break;
                
            case XTIFFField.TIFF_LONG:
                long[] lvalues = new long[count];
                for (j = 0; j < count; j++) {
                    lvalues[j] = readUnsignedInt(stream);
                }
                obj = lvalues;
                break;
                
            case XTIFFField.TIFF_RATIONAL:
                long[][] llvalues = new long[count][2];
                for (j = 0; j < count; j++) {
                    llvalues[j][0] = readUnsignedInt(stream);
                    llvalues[j][1] = readUnsignedInt(stream);
                }
		obj = llvalues;
                break;
                
            case XTIFFField.TIFF_SSHORT:
                short[] svalues = new short[count];
                for (j = 0; j < count; j++) {
		    svalues[j] = readShort(stream);
                }
                obj = svalues;
                break;
                
            case XTIFFField.TIFF_SLONG:
                int[] ivalues = new int[count];
                for (j = 0; j < count; j++) {
                    ivalues[j] = readInt(stream);
                }
                obj = ivalues;
                break;
                
            case XTIFFField.TIFF_SRATIONAL:
                int[][] iivalues = new int[count][2];
                for (j = 0; j < count; j++) {
                    iivalues[j][0] = readInt(stream);
                    iivalues[j][1] = readInt(stream);
                }
                obj = iivalues;
                break;

            case XTIFFField.TIFF_FLOAT:
                float[] fvalues = new float[count];
                for (j = 0; j < count; j++) {
                    fvalues[j] = readFloat(stream);
                }
                obj = fvalues;
                break;

            case XTIFFField.TIFF_DOUBLE:
                double[] dvalues = new double[count];
                for (j = 0; j < count; j++) {
                    dvalues[j] = readDouble(stream);
                }
                obj = dvalues;
                break;

            default:
                System.err.println(JaiI18N.getString("XTIFFDirectory0"));
                break;
            }
	    return obj;
    }

      /**
       * Method for reading a field from stream. Positions
       * stream at the next field location.
       */
    private XTIFFField readField ()
       throws IOException, ArrayIndexOutOfBoundsException 
    {
            int j;
            int tag = readUnsignedShort(stream);
            int type = readUnsignedShort(stream);
            int count = (int)readUnsignedInt(stream);
            int value = 0;

            // The place to return to to read the next tag
            long nextTagOffset = stream.getFilePointer() + 4;

	    try {
	       // If the tag data can't fit in 4 bytes, the next 4 bytes
	       // contain the starting offset of the data
	        if (count*sizeOfType(type) > 4) {
		    value = (int)(readUnsignedInt(stream));
		    stream.seek(value);
	        }
	    } catch (ArrayIndexOutOfBoundsException ae) {
		System.err.println(tag + " " + 
				   JaiI18N.getString("XTIFFDirectory4"));
		// if the data type is unknown we should skip this TIFF Field
		stream.seek(nextTagOffset);
		throw ae;
	    }

	    Object obj = readFieldValue(tag,type,count);

		// Position stream at next field and return this one
	    stream.seek(nextTagOffset);

            return createField(tag, type, count, obj);
    }


    // Methods to read primitive data types from the stream

    protected short readShort(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            return stream.readShort();
        } else {
            return stream.readShortLE();
        }
    }

    protected int readUnsignedShort(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            int val=stream.readUnsignedShort();
            return val;
        } else {
            int val= stream.readUnsignedShortLE();
            return val;
        }
    }

    protected int readInt(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            return stream.readInt();
        } else {
            return stream.readIntLE();
        }
    }

    protected long readUnsignedInt(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            return stream.readUnsignedInt();
        } else {
            return stream.readUnsignedIntLE();
        }
    }

    protected long readLong(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            return stream.readLong();
        } else {
            return stream.readLongLE();
        }
    }

    protected float readFloat(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            return stream.readFloat();
        } else {
            return stream.readFloatLE();
        }
    }

    protected double readDouble(SeekableStream stream)
        throws IOException {
        if (isBigEndian) {
            return stream.readDouble();
        } else {
            return stream.readDoubleLE();
        }
    }

     // Static methods used by the public static method below

    private static int readUnsignedShort(SeekableStream stream,
                                         boolean isBigEndian)
        throws IOException {
        if (isBigEndian) {
            return stream.readUnsignedShort();
        } else {
            return stream.readUnsignedShortLE();
        }
    }

    private static long readUnsignedInt(SeekableStream stream,
                                        boolean isBigEndian) 
        throws IOException {
        if (isBigEndian) {
            return stream.readUnsignedInt();
        } else {
            return stream.readUnsignedIntLE();
        }
    }

    // Utilities

    /**
     * Returns the number of image directories (subimages) stored in a
     * given TIFF file, represented by a <code>SeekableStream</code>.
     */
    public static int getNumDirectories(SeekableStream stream)
        throws IOException{
        long pointer = stream.getFilePointer(); // Save stream pointer

        stream.seek(0L);
        int endian = stream.readUnsignedShort();
        if (!isValidEndianTag(endian)) {
            throw new 
		IllegalArgumentException(JaiI18N.getString("XTIFFDirectory1"));
        }
        boolean isBigEndian = (endian == 0x4d4d);
        int magic = readUnsignedShort(stream, isBigEndian);
        if (magic != 42) {
            throw new 
		IllegalArgumentException(JaiI18N.getString("XTIFFDirectory2"));
        }
        
        stream.seek(4L);
        long offset = readUnsignedInt(stream, isBigEndian);

        int numDirectories = 0;
        while (offset != 0L) {
            ++numDirectories;

            stream.seek(offset);
            int entries = readUnsignedShort(stream, isBigEndian);
            stream.skip(12*entries);
            offset = readUnsignedInt(stream, isBigEndian);
        }
      
        stream.seek(pointer); // Reset stream pointer
        return numDirectories;
    }


    /**
     * Returns a boolean indicating whether the byte order used in the
     * the TIFF file is big-endian (i.e. whether the byte order is from  
     * the most significant to the least significant)
     */
    public boolean isBigEndian() {
	return isBigEndian;
    }

    /**
     * Specifies the type of compression to be used. The compression type
     * specified will be honored only if it is compatible with the image
     * being written out. 
     *
     * @param compression    The compression type.
     */
    public void setCompression(int compression) {
	//this.compression = compression;
	// Check to see if compression supported
	// Add Field
        addField(XTIFF.TIFFTAG_COMPRESSION,XTIFFField.TIFF_SHORT,1,
		 new char[] {(char)compression});
    }

    /**
     * Return the type of compression indicated in the
     * TIFF fields, or XTIFF.COMPRESSION_NON if not
     * specified.
     */
    public int getCompression() {
        if (getField(XTIFF.TIFFTAG_COMPRESSION)==null)
	    return XTIFF.COMPRESSION_NONE;
	return (int)getFieldAsLong(XTIFF.TIFFTAG_COMPRESSION);
    }

    /**
     * If set, the data will be written out in tiled format, instead of
     * in strips.
     *
     * @param isTiled     Specifies whether the image data should be 
     *                       wriiten out in tiled format.
     */
    public void setIsTiled(boolean isTiled) {
	this._isTiled = isTiled;
    }

	/**
	 * Constructs a tile codec for decoding data, using the
	 * compression defined in the current directory.
	 * @param param the encoding param
	 * @see XTIFFTileCodec
	 */
    public XTIFFTileCodec createTileCodec(XTIFFDecodeParam param) 
	throws IOException
    {
	int compression = getCompression();
	XTIFFTileCodec codec = getTileCodec(compression);
	if (codec==null) 
	   throw new IOException("Compression type ("
		+compression+") not supported");
	return codec.create(param);
    }

	/**
	 * Constructs a tile codec for encoding data, using the
	 * compression defined in the current directory.
	 * @param param the encoding param
	 * @see XTIFFTileCodec
	 */
    public XTIFFTileCodec createTileCodec(XTIFFEncodeParam param) 
	throws IOException
    {
	int compression = getCompression();
	XTIFFTileCodec codec = getTileCodec(compression);
	if (codec==null) 
	   throw new IOException("Compression type ("
		+compression+") not supported");
	return codec.create(param);
    }

	/**
	 * Set the XTIFFFactory, which is used to
	 * construct the XTIFFDirectory object assigned as a
	 * "tiff.directory" property in the resulting jai image.
	 *
         * @param fact the factory to register. The factory is 
	 * guaranteed to always be non-null; if a null is passed
	 * in then the default XTIFFFactory is used.
	 * a null object is passed in
         * @see XTIFFFactory
	 */
    public static void setFactory(XTIFFFactory fact) {
	if (fact == null)
	  factory = new XTIFFFactory();
	else factory = fact;
    }

    /**
     * Constructs a XTIFFDirectory from a SeekableStream.
     * The directory parameter specifies which directory to read from
     * the linked list present in the stream; directory 0 is normally
     * read but it is possible to store multiple images in a single
     * TIFF file by maintaing multiple directories.
     *
     * @param stream a SeekableStream to read from.
     * @param directory the index of the directory to read.
     * @see XTIFFFactory
     */
    public static XTIFFDirectory create(SeekableStream stream, int directory)
        throws IOException {
	return factory.createDirectory(stream,directory);
    }

    /**
     * Constructs a TIFFDirectory by reading a SeekableStream.
     * The ifd_offset parameter specifies the stream offset from which
     * to begin reading; this mechanism is sometimes used to store
     * private IFDs within a TIFF file that are not part of the normal
     * sequence of IFDs. Uses the XTIFFFactory to do this, so
     * to extend the directory class, the factory method should be
     * extended and registered instead of this one.
     *
     * @param stream a SeekableStream to read from.
     * @param ifd_offset the long byte offset of the directory.
     * @see XTIFFFactory
     */
    public static XTIFFDirectory create(SeekableStream stream, long ifd_offset)
        throws IOException {
	return factory.createDirectory(stream,ifd_offset);
    }

    /**
     * Constructs an XTIFFDirectory from the currently.
     * registered XTIFFDirectory factory.
     * @see XTIFFFactory
     */
    public static XTIFFDirectory create() {
	return factory.createDirectory();
    }

	/**
	 * Return the currently registered XTIFFTileCodec
	 * for this compression type. Used by the XTIFFImage
	 * to decode the compression data.
	 * @see XTIFFTileCodec
	 */
    public static XTIFFTileCodec getTileCodec(int comp) {
	return (XTIFFTileCodec)tileCodecs.get(new Integer(comp));
    }

	/**
	 * UnRegister the XTIFFTileCodec corresponding to the 
	 * TIFF compression type.
	 * @param comp The TIFF compression code indicated 
	 */
    public static void unRegisterTileCodec(int comp) {
	XTIFFTileCodec cod=getTileCodec(comp);
	tileCodecs.remove(cod);
    }

	/**
	 * Register a new XTIFFTileCodec for encoding and decoding
	 * compressed TIFF image data. This overrides any existing
	 * codec previously registered.
	 * @param comp The TIFF compression code indicated by the
	 * @param codec The codec to register.
	 *    XTIFF.TIFFTAG_COMPRESSION field.
	 * @see XTIFFTileCodec
	 */
    public static void registerTileCodec(int comp,XTIFFTileCodec codec) {
	tileCodecs.put(new Integer(comp),codec);
    }

	/**
	 * Get the JAI Image decoded type. This method is
	 * called by the XTIFFTileCodeImpl object during the
	 * decode() method to determine what type of colorspace
	 * and sample model to use.
	 */ 
    public int getImageType() {
	return imageType;
    }

	/**
	 * Set the JAI Image decoded type. This method is
	 * called by the XTIFFImage constructor to indicate
	 * to the XTIFFTileCodec what type of colorspace and
	 * sample model to use. The types are enumerated in
	 * the XTIFF class.
	 * @see XTIFF
	 * @see XTIFFImage
	 * @see XTIFFTileCodec
	 */
    public void setImageType(int image_type) {
	imageType=image_type;
    }
}
